home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / zip.zip / ZIP.C < prev    next >
C/C++ Source or Header  |  1992-09-22  |  26KB  |  867 lines

  1. /*
  2.  
  3.  Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
  4.  Permission is granted to any individual or institution to use, copy, or
  5.  redistribute this software so long as all of the original files are included
  6.  unmodified, that it is not sold for profit, and that this copyright notice
  7.  is retained.
  8.  
  9. */
  10.  
  11. /*
  12.  *  zip.c by Mark Adler.
  13.  */
  14.  
  15. #include "revision.h"
  16. #include "zip.h"
  17. #include <signal.h>
  18.  
  19. #define PWLEN 80        /* Input buffer size for reading encryption key */
  20. #define MAXCOM 256      /* Maximum one-line comment size */
  21.  
  22.  
  23. /* Local option flags */
  24. #define DELETE  0
  25. #define ADD     1
  26. #define UPDATE  2
  27. #define FRESHEN 3
  28. local int action = ADD; /* one of ADD, UPDATE, FRESHEN, or DELETE */
  29. local int comadd = 0;   /* 1=add comments for new files */
  30. local int zipedit = 0;  /* 1=edit zip comment and all file comments */
  31. local int dispose = 0;  /* 1=remove files after put in zip file */
  32. local int latest = 0;   /* 1=set zip file time to time of latest file */
  33. local ulg before = 0;   /* 0=ignore, else exclude files before this time */
  34.  
  35.  
  36. /* Temporary zip file name and file pointer */
  37. local char *tempzip;
  38. local FILE *tempzf;
  39.  
  40.  
  41. /* Local functions */
  42. #ifdef PROTO
  43.    local void freeup(void);
  44.    local void leave(int);
  45.    local void err(int, char *);
  46.    local void handler(int);
  47.    local void license(void);
  48.    local void help(void);
  49.    void main(int, char **);
  50. #endif /* PROTO */
  51.  
  52.  
  53.  
  54. local void freeup()
  55. /* Free all allocations in the found list and the zfiles list */
  56. {
  57.   struct flist far *f;  /* steps through found list */
  58.   struct zlist far *z;  /* pointer to next entry in zfiles list */
  59.  
  60.   for (f = found; f != NULL; f = fexpel(f))
  61.     ;
  62.   while (zfiles != NULL)
  63.   {
  64.     z = zfiles->nxt;
  65.     free((voidp *)(zfiles->name));
  66.     free((voidp *)(zfiles->zname));
  67.     if (zfiles->ext)
  68.       free((voidp *)(zfiles->extra));
  69.     if (zfiles->cext && zfiles->cextra != zfiles->extra)
  70.       free((voidp *)(zfiles->cextra));
  71.     if (zfiles->com)
  72.       free((voidp *)(zfiles->comment));
  73.     farfree((voidp far *)zfiles);
  74.     zfiles = z;
  75.     zcount--;
  76.   }
  77. }
  78.  
  79.  
  80. local void leave(e)
  81. int e;                  /* exit code */
  82. /* Process -o and -m options (if specified), free up malloc'ed stuff, and
  83.    exit with the code e. */
  84. {
  85.   int r;                /* return value from trash() */
  86.   ulg t;                /* latest time in zip file */
  87.   struct zlist far *z;  /* pointer into zfile list */
  88.  
  89.   /* If latest, set time to zip file to latest file in zip file */
  90.   if (latest)
  91.   {
  92.     diag("changing time of zip file to time of latest file in it");
  93.     /* find latest time in zip file */
  94.     t = zfiles->tim;
  95.     for (z = zfiles->nxt; z != NULL; z = z->nxt)
  96.       if (t < z->tim)
  97.         t = z->tim;
  98.     /* set modified time of zip file to that time */
  99.     stamp(zipfile, t);
  100.   }
  101.   if (tempath != NULL)
  102.   {
  103.     free((voidp *)tempath);
  104.     tempath = NULL;
  105.   }
  106.   if (zipfile != NULL)
  107.   {
  108.     free((voidp *)zipfile);
  109.     zipfile = NULL;
  110.   }
  111.  
  112.  
  113.   /* If dispose, delete all files in the zfiles list that are marked */
  114.   if (dispose)
  115.   {
  116.     diag("deleting files that were added to zip file");
  117.     if ((r = trash()) != ZE_OK)
  118.       err(r, "was deleting moved files and directories");
  119.   }
  120.  
  121.  
  122.   /* Done! */
  123.   freeup();
  124. #ifdef VMS
  125.   exit(0);
  126. #else /* !VMS */
  127.   exit(e);
  128. #endif /* ?VMS */
  129. }
  130.  
  131.  
  132. local void err(c, h)
  133. int c;                  /* error code from the ZE_ class */
  134. char *h;                /* message about how it happened */
  135. /* Issue a message for the error, clean up files and memory, and exit. */
  136. {
  137.   if (PERR(c))
  138.     perror("zip error");
  139.   fprintf(stderr, "zip error: %s (%s)\n", errors[c-1], h);
  140.   if (shract)
  141.   {
  142.     shr_clear();
  143.     shract = 0;
  144.   }
  145. #ifndef NOIMPLODE
  146.   if (impact)
  147.   {
  148.     imp_clear();
  149.     impact = 0;
  150.   }
  151. #endif /* !NOIMPLODE */
  152.   if (tempzf != NULL)
  153.     fclose(tempzf);
  154.   if (tempzip != NULL)
  155.   {
  156.     destroy(tempzip);
  157.     if (tempzip != zipfile)
  158.       free((voidp *)tempzip);
  159.   }
  160.   if (key != NULL)
  161.     free((voidp *)key);
  162.   if (tempath != NULL)
  163.     free((voidp *)tempath);
  164.   if (zipfile != NULL)
  165.     free((voidp *)zipfile);
  166.   freeup();
  167. #ifdef VMS
  168.   exit(0);
  169. #else /* !VMS */
  170.   exit(c);
  171. #endif /* ?VMS */
  172. }
  173.  
  174.  
  175. local void handler(s)
  176. int s;                  /* signal number (ignored) */
  177. /* Upon getting a user interrupt, turn echo back on for tty and abort
  178.    cleanly using err(). */
  179. {
  180. #ifndef MSVMS
  181. #ifndef EXPORT
  182.   echon();
  183. #endif /* !EXPORT */
  184.   putc('\n', stderr);
  185. #endif /* !MSVMS */
  186.   err(ZE_ABORT, "aborting");
  187.   s++;                                  /* keep some compilers happy */
  188. }
  189.  
  190.  
  191. void warn(a, b)
  192. char *a, *b;            /* message strings juxtaposed in output */
  193. /* Print a warning message to stderr and return. */
  194. {
  195.   fprintf(stderr, "zip warning: %s%s\n", a, b);
  196. }
  197.  
  198.  
  199. local void license()
  200. /* Print license information to stdout. */
  201. {
  202.   extent i;             /* counter for copyright array */
  203.  
  204.   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
  205.     puts(copyright[i]);
  206.   for (i = 0; i < sizeof(disclaimer)/sizeof(char *); i++)
  207.     puts(disclaimer[i]);
  208. }
  209.  
  210.  
  211. local void help()
  212. /* Print help (along with license info) to stdout. */
  213. {
  214.   extent i;             /* counter for help array */
  215.  
  216.   /* help array */
  217.   static char *text[] = {
  218. "",
  219. "Zip %d.%d (%s)",
  220. "Usage:  zip [-options] [-b path] [-t mmddyy] zipfile list [-x list]",
  221. "  the default action is to add or replace zipfile entries from list, which",
  222. "  can include the special name - to read names from stdin.",
  223. "  -f   freshen: only changed files  -u   update: only changed or new files",
  224. "  -d   delete entries in zipfile    -m   move into zipfile (delete files)",
  225. "  -k   simulate PKZIP made zipfile  -g   allow growing existing zipfile",
  226. "  -h   show this help               -l   show software license",
  227. "  -r   recurse into directories     -j   junk (don't record) directory names",
  228. "  -i   implode only                 -s   shrink only",
  229. "  -0   compress faster              -9   compress better",
  230. "  -q   quiet operation              -n   don't compress special suffixes",
  231. "  -c   add one-line comments        -z   add zipfile comment",
  232. "  -b   use \"path\" for temp files    -t   only do files after \"mmddyy\"",
  233. #ifdef EXPORT
  234. "  -o   make zipfile as old as latest entry",
  235. #else /* !EXPORT */
  236. "  -e   encrypt  (-ee verify key)    -o   make zipfile as old as latest entry",
  237. #endif /* ?EXPORT */
  238. #ifdef VMS
  239. "  -w   append the VMS version number to the name stored in the zip file",
  240. #endif /* VMS */
  241. #ifdef S_IFLNK
  242. "  -y   store symbolic links as the link instead of the referenced file",
  243. #endif /* !S_IFLNK */
  244. "  -x   exclude the names that follow from those operated on"
  245.   };
  246.  
  247.   for (i = 0; i < sizeof(copyright)/sizeof(char *); i++)
  248.     puts(copyright[i]);
  249.   for (i = 0; i < sizeof(text)/sizeof(char *); i++)
  250.   {
  251.     printf(text[i], REVISION / 10, REVISION % 10, REVDATE);
  252.     putchar('\n');
  253.   }
  254. }
  255.  
  256.  
  257. /* Do command line expansion for MSDOS and VMS */
  258. #ifdef MSVMS
  259. #  define PROCNAME(n) (action==ADD||action==UPDATE?wild(n):procname(n))
  260. #else /* !MSVMS */
  261. #  define PROCNAME(n) procname(n)
  262. #endif /* ?MSVMS */
  263.  
  264.  
  265. void main(argc, argv)
  266. int argc;               /* number of tokens in command line */
  267. char **argv;            /* command line tokens */
  268. /* Add, update, freshen, or delete zip entries in a zip file.  See the
  269.    command help in help() above. */
  270. {
  271.   int a;                /* attributes of zip file */
  272.   ulg c;                /* start of central directory */
  273.   int d;                /* true if just adding to a zip file */
  274.   char *e;              /* malloc'd comment buffer */
  275.   struct flist far *f;  /* steps through found linked list */
  276.   int i;                /* arg counter, root directory flag */
  277.   int k;                /* next argument type, marked counter,
  278.                            comment size, entry count */
  279.   ulg n;                /* total of entry len's */
  280.   int o;                /* true if there were any ZE_OPEN errors */
  281.   char *p;              /* steps through option arguments */
  282.   int r;                /* temporary variable */
  283.   ulg t;                /* file time, length of central directory */
  284.   struct zlist far *v;  /* temporary variable */
  285.   struct zlist far * far *w;    /* pointer to last link in zfiles list */
  286.   FILE *x, *y;          /* input and output zip files */
  287.   struct zlist far *z;  /* steps through zfiles linked list */
  288.  
  289.  
  290.   /* Process arguments */
  291.   diag("processing arguments");
  292.   if (argc == 1)
  293.   {
  294.     help();
  295.     exit(0);
  296.   }
  297.   zipfile = tempzip = NULL;
  298.   tempzf = NULL;
  299.   d = 0;                        /* disallow adding to a zip file */
  300.   signal(SIGINT, handler);
  301.   signal(SIGTERM, handler);
  302.   k = 0;                        /* Next non-option argument type */
  303.   for (i = 1; i < argc; i++)
  304.   {
  305.     if (argv[i][0] == '-')
  306.       if (argv[i][1])
  307.         for (p = argv[i]+1; *p; p++)
  308.           switch(*p)
  309.           {
  310.             case '0':  case '1':  case '2':  case '3':  case '4':
  311.             case '5':  case '6':  case '7':  case '8':  case '9':
  312.                         /* Set the compression efficacy */
  313.               level = *p - '0';  break;
  314.             case 'b':   /* Specify path for temporary file */
  315.               if (k != 0)
  316.                 err(ZE_PARMS, "use -b before zip file name");
  317.               else
  318.                 k = 1;          /* Next non-option is path */
  319.               break;
  320.             case 'c':   /* Add comments for new files in zip file */
  321.               comadd = 1;  break;
  322.             case 'd':   /* Delete files from zip file */
  323.               if (action != ADD)
  324.                 err(ZE_PARMS, "specify just one action");
  325.               action = DELETE;
  326.               break;
  327. #ifndef EXPORT
  328.             case 'e':   /* Encrypt */
  329.               e = key == NULL ? (char *)NULL : key;
  330.               if ((key = malloc(PWLEN+1)) == NULL)
  331.                 err(ZE_MEM, "was getting encryption password");
  332.               if (getp(e == NULL ? "Enter password: " : "Verify password: ",
  333.                        key, PWLEN+1) == NULL)
  334.                 err(ZE_PARMS, "stderr is not a tty");
  335.               if (e != NULL)
  336.               {
  337.                 r = strcmp(key, e);
  338.                 free((voidp *)e);
  339.                 if (r)
  340.                   err(ZE_PARMS, "password not verified");
  341.               }
  342.               break;
  343. #endif /* !EXPORT */
  344.             case 'f':   /* Freshen zip file--overwrite only */
  345.               if (action != ADD)
  346.                 err(ZE_PARMS, "specify just one action");
  347.               action = FRESHEN;
  348.               break;
  349.             case 'g':   /* Allow appending to a zip file */
  350.               d = 1;  break;
  351.             case 'h':   /* Help */
  352.               help();  break;
  353.             case 'i':   /* Implode only */
  354.               method = IMPLODE;  break;
  355.             case 'j':   /* Junk directory names */
  356.               pathput = 0;  break;
  357.             case 'k':   /* Make entries using DOS names (k for Katz) */
  358.               dosify = 2;  break;
  359.             case 'l':   /* Show license, version */
  360.               license();  break;
  361.             case 'm':   /* Delete files added or updated in zip file */
  362.               dispose = 1;  break;
  363.             case 'n':   /* Don't compress files with a special suffix */
  364.               if ((special = getenv("NOZIP")) == NULL)
  365.                 special = ".Z:.zip:.zoo:.arc";
  366. #ifndef OS2
  367. #ifdef MSDOS
  368.               strupr(special);
  369. #endif /* MSDOS */
  370. #endif /* !OS2 */
  371.               break;
  372.             case 'o':   /* Set zip file time to time of latest file in it */
  373.               latest = 1;  break;
  374.             case 'p':   /* Store path with name */
  375.               break;            /* (do nothing as annoyance avoidance) */
  376.             case 'q':   /* Quiet operation */
  377.               noisy = 0;  break;
  378.             case 'r':   /* Recurse into subdirectories */
  379.               recurse = 1;  break;
  380.             case 's':   /* Shrink only */
  381.               method = SHRINK;  break;
  382.             case 't':   /* Exclude files earlier than specified date */
  383.               if (before)
  384.                 err(ZE_PARMS, "can only have one -t");
  385.               k = 2;  break;
  386.             case 'u':   /* Update zip file--overwrite only if newer */
  387.               if (action != ADD)
  388.                 err(ZE_PARMS, "specify just one action");
  389.               action = UPDATE;
  390.               break;
  391.             case 'v':   /* Mention oddities in zip file structure */
  392.               verbose = 1;
  393.               break;
  394. #ifdef VMS
  395.             case 'w':   /* Append the VMS version number */
  396.               vmsver = 1;  break;
  397. #endif /* VMS */
  398.             case 'x':   /* Exclude following files */
  399.               if (k != 4 &&
  400.                   (k != 3 || (action != UPDATE && action != FRESHEN)))
  401.                 err(ZE_PARMS, "nothing to exclude (-x) from");
  402.               if (k == 3)       /* must be -u or -f */
  403.                 for (z = zfiles; z != NULL; z = z->nxt)
  404.                   z->mark = 1;  /* mark all of them */
  405.               k = 5;
  406.               if ((r = exclude()) != ZE_OK)
  407.                 if (r == ZE_PARMS)
  408.                   err(r, "cannot repeat names in zip file");
  409.                 else
  410.                   err(r, "was processing list of files");
  411.               break;
  412. #ifdef S_IFLNK
  413.             case 'y':   /* Store symbolic links as such */
  414.               linkput = 1;  break;
  415. #endif /* !S_IFLNK */
  416.             case 'z':   /* Edit zip file comment */
  417.               zipedit = 1;  break;
  418.             default:
  419.             {
  420.               sprintf(errbuf, "no such option: %c", *p);
  421.               err(ZE_PARMS, errbuf);
  422.             }
  423.           }
  424.       else              /* just a dash */
  425.         if (k < 3)
  426.           err(ZE_PARMS, "zip file cannot be stdin");
  427.         else            /* read names from stdin */
  428.           while ((p = getnam(errbuf)) != NULL)
  429.           {
  430.             if ((r = PROCNAME(p)) != ZE_OK)
  431.               if (r == ZE_MISS)
  432.                 warn("name not matched: ", p);
  433.               else
  434.                 err(r, p);
  435.           }
  436.     else                /* not an option */
  437.     {
  438.       switch (k)
  439.       {
  440.         case 0:
  441.           if ((zipfile = ziptyp(argv[i])) == NULL)
  442.             err(ZE_MEM, "was processing arguments");
  443.           if ((r = readzipfile()) != ZE_OK)
  444.             err(r, zipfile);
  445.           found = NULL;
  446.           fnxt = &found;
  447.           k = 3;
  448.           break;
  449.         case 1:
  450.           if ((tempath = malloc(strlen(argv[i]) + 1)) == NULL)
  451.             err(ZE_MEM, "was processing arguments");
  452.           strcpy(tempath, argv[i]);
  453.           k = 0;
  454.           break;
  455.         case 2:
  456.         {
  457.           int yy, mm, dd;       /* results of sscanf() */
  458.  
  459.           if (sscanf(argv[i], "%2d%2d%2d", &mm, &dd, &yy) != 3 ||
  460.               mm < 1 || mm > 12 || dd < 1 || dd > 31)
  461.             err(ZE_PARMS, "invalid date entered for -t option");
  462.           before = dostime(yy + (yy < 80 ? 2000 : 1900), mm, dd, 0, 0, 0);
  463.           k = 0;
  464.           break;
  465.         }
  466.         case 3:  case 4:  case 5:
  467.           if ((r = PROCNAME(argv[i])) != ZE_OK)
  468.             if (r == ZE_MISS)
  469.               warn("name not matched: ", argv[i]);
  470.             else
  471.               err(r, argv[i]);
  472.           if (k == 3)
  473.             k = 4;
  474.       }
  475.     }
  476.   }
  477.   if (k < 3)
  478.     exit(0);                    /* No zip file, don't complain */
  479.   if (k != 5)                   /* Clean up selections */
  480.   {
  481.     if (k == 3 && (action == UPDATE || action == FRESHEN))
  482.       for (z = zfiles; z != NULL; z = z->nxt)
  483.         z->mark = 1;                    /* if -u or -f with no args, do all */
  484.     if ((r = exclude()) != ZE_OK)       /* remove duplicates in found list */
  485.       if (r == ZE_PARMS)
  486.         err(r, "cannot repeat names in zip file");
  487.       else
  488.         err(r, "was processing list of files");
  489.   }
  490.   if (zcount)
  491.     free((voidp *)zsort);
  492.  
  493.  
  494.   /* Check option combinations */
  495.   if (action == DELETE && (method != BEST || dispose || recurse ||
  496.       dosify || key != NULL || comadd || zipedit))
  497.     err(ZE_PARMS, "invalid option(s) used with -d");
  498.   if (linkput && dosify)
  499.     err(ZE_PARMS, "can't use -y with -k");
  500.  
  501.   /* If -b not specified, make temporary path the same as the zip file */
  502. #ifdef MSDOS
  503.   if (tempath == NULL && ((p = strrchr(zipfile, '/')) != NULL ||
  504.                           (p = strrchr(zipfile, '\\')) != NULL ||
  505.                           (p = strrchr(zipfile, ':')) != NULL))
  506.   {
  507.     if (*p == ':')
  508.       p++;
  509. #else /* !MSDOS */
  510.   if (tempath == NULL && (p = strrchr(zipfile, '/')) != NULL)
  511.   {
  512. #endif /* ?MSDOS */
  513.     if ((tempath = malloc((int)(p - zipfile) + 1)) == NULL)
  514.       err(ZE_MEM, "was processing arguments");
  515.     r = *p;  *p = 0;
  516.     strcpy(tempath, zipfile);
  517.     *p = (char)r;
  518.   }
  519.  
  520.   /* If under MSDOS, force entries to look like made by PKZIP */
  521. #ifndef OS2
  522. #ifdef MSDOS
  523.   dosify = 1;
  524. #endif /* MSDOS */
  525. #endif /* !OS2 */
  526.  
  527.  
  528.   /* For each marked entry, if not deleting, check if it exists, and if
  529.      updating or freshening, compare date with entry in old zip file.
  530.      Unmark if it doesn't exist or is too old, else update marked count. */
  531.   diag("stating marked entries");
  532.   k = 0;                        /* Initialize marked count */
  533.   for (z = zfiles; z != NULL; z = z->nxt)
  534.     if (z->mark)
  535.       if (action != DELETE &&
  536.                 ((t = filetime(z->name, (ulg *)NULL, (long *)NULL)) == 0 ||
  537.                  t < before ||
  538.                  ((action == UPDATE || action == FRESHEN) && t <= z->tim)))
  539.       {
  540.         z->mark = 0;
  541.         z->trash = t && t >= before;    /* delete if -um or -fm */
  542.         if (verbose)
  543.           printf("zip diagnostic: %s %s\n", z->name,
  544.                  z->trash ? "up to date" : "missing or early");
  545.       }
  546.       else
  547.         k++;
  548.  
  549.  
  550.   /* Remove entries from found list that do not exist or are too old */
  551.   diag("stating new entries");
  552.   for (f = found; f != NULL;)
  553.     if (action == DELETE || action == FRESHEN ||
  554.         (t = filetime(f->name, (ulg *)NULL, (long *)NULL)) == 0 ||
  555.         t < before || strcmp(f->name, zipfile) == 0)
  556.       f = fexpel(f);
  557.     else
  558.       f = f->nxt;
  559.  
  560.  
  561.   /* Make sure there's something left to do */
  562.   if (k == 0 && found == NULL && !(zfiles != NULL && (latest || zipedit)))
  563.     if (action == UPDATE || action == FRESHEN)
  564.       leave(ZE_OK);
  565.     else
  566.       err(ZE_NONE, zipfile);
  567.   d = (d && k == 0 && zfiles != NULL);  /* d true if just appending */
  568.  
  569.  
  570.   /* Before we get carried away, make sure zip file is writeable */
  571.   if ((x = fopen(zipfile, zfiles == NULL ? FOPW : FOPM)) == NULL)
  572.     err(ZE_CREAT, zipfile);
  573.   fclose(x);
  574.   a = getfileattr(zipfile);
  575.   if (zfiles == NULL)
  576.     destroy(zipfile);
  577.  
  578.  
  579.   /* Open zip file and temporary output file */
  580.   diag("opening zip file and creating temporary zip file");
  581.   x = NULL;
  582.   if (d)
  583.   {
  584.     if ((y = fopen(zipfile, FOPM)) == NULL)
  585.       err(ZE_NAME, zipfile);
  586.     tempzip = zipfile;
  587.     tempzf = y;
  588. #ifdef MSDOS
  589.     {
  590.       char *zipbuf;
  591.  
  592.       zipbuf = (char *)malloc(BSZ);
  593.       if (zipbuf == NULL)
  594.         err(ZE_MEM, tempzip);
  595.       setbuf(y, zipbuf);
  596.     }
  597. #endif /* MSDOS */
  598.     if (fseek(y, cenbeg, SEEK_SET))
  599.       err(ferror(y) ? ZE_READ : ZE_EOF, zipfile);
  600.   }
  601.   else
  602.   {
  603.     if (zfiles != NULL && (x = fopen(zipfile, FOPR)) == NULL)
  604.       err(ZE_NAME, zipfile);
  605.     if ((tempzip = tempname('Z')) == NULL)
  606.       err(ZE_MEM, tempzip);
  607.     if ((tempzf = y = fopen(tempzip, FOPW)) == NULL)
  608.       err(ZE_TEMP, tempzip);
  609.     if (zipbeg && (r = fcopy(x, y, zipbeg)) != ZE_OK)
  610.       err(r, r == ZE_TEMP ? tempzip : zipfile);
  611.   }
  612.   o = 0;                                /* no ZE_OPEN errors yet */
  613.  
  614.  
  615.   /* Process zip file, updating marked files */
  616.   if (zfiles != NULL)
  617.     diag("going through old zip file");
  618.   w = &zfiles;
  619.   while ((z = *w) != NULL)
  620.     if (z->mark)
  621.     {
  622.       /* if not deleting, zip it up */
  623.       if (action != DELETE)
  624.       {
  625.         if (noisy)
  626.         {
  627.           printf("updating %s", z->zname);
  628.           fflush(stdout);
  629.         }
  630.         if ((r = zipup(z, y)) != ZE_OK && r != ZE_OPEN)
  631.         {
  632.           if (noisy)
  633.           {
  634.             putchar('\n');
  635.             fflush(stdout);
  636.           }
  637.           sprintf(errbuf, "was zipping %s", z->name);
  638.           err(r, errbuf);
  639.         }
  640.         if (r == ZE_OPEN)
  641.         {
  642.           o = 1;
  643.           if (noisy)
  644.           {
  645.             putchar('\n');
  646.             fflush(stdout);
  647.           }
  648.           perror("zip warning");
  649.           warn("could not open for reading: ", z->name);
  650.           warn("will just copy entry over: ", z->zname);
  651.           if ((r = zipcopy(z, x, y)) != ZE_OK)
  652.           {
  653.             sprintf(errbuf, "was copying %s", z->zname);
  654.             err(r, errbuf);
  655.           }
  656.           z->mark = 0;
  657.         }
  658.         w = &z->nxt;
  659.       }
  660.       else
  661.       {
  662.         if (noisy)
  663.         {
  664.           printf("deleting %s\n", z->zname);
  665.           fflush(stdout);
  666.         }
  667.         v = z->nxt;                     /* delete entry from list */
  668.         free((voidp *)(z->name));
  669.         free((voidp *)(z->zname));
  670.         if (z->ext)
  671.           free((voidp *)(z->extra));
  672.         if (z->cext && z->cextra != z->extra)
  673.           free((voidp *)(z->cextra));
  674.         if (z->com)
  675.           free((voidp *)(z->comment));
  676.         farfree((voidp far *)z);
  677.         *w = v;
  678.         zcount--;
  679.       }
  680.     }
  681.     else
  682.     {
  683.       /* copy the original entry verbatim */
  684.       if (!d && (r = zipcopy(z, x, y)) != ZE_OK)
  685.       {
  686.         sprintf(errbuf, "was copying %s", z->zname);
  687.         err(r, errbuf);
  688.       }
  689.       w = &z->nxt;
  690.     }
  691.   if (x != NULL)
  692.     fclose(x);
  693.  
  694.  
  695.   /* Process the edited found list, adding them to the zip file */
  696.   diag("zipping up new entries, if any");
  697.   for (f = found; f != NULL; f = fexpel(f))
  698.   {
  699.     /* add a new zfiles entry and set the name */
  700.     if ((z = (struct zlist far *)farmalloc(sizeof(struct zlist))) == NULL)
  701.       err(ZE_MEM, "was adding files to zip file");
  702.     z->nxt = NULL;
  703.     z->name = f->name;
  704.     f->name = NULL;
  705.     z->zname = f->zname;
  706.     f->zname = NULL;
  707.     z->ext = z->cext = z->com = 0;
  708.     z->mark = 1;
  709.     /* zip it up */
  710.     if (noisy)
  711.     {
  712.       printf("adding %s", z->zname);
  713.       fflush(stdout);
  714.     }
  715.     if ((r = zipup(z, y)) != ZE_OK  && r != ZE_OPEN)
  716.     {
  717.       if (noisy)
  718.       {
  719.         putchar('\n');
  720.         fflush(stdout);
  721.       }
  722.       sprintf(errbuf, "was zipping %s", z->name);
  723.       err(r, errbuf);
  724.     }
  725.     if (r == ZE_OPEN)
  726.     {
  727.       o = 1;
  728.       if (noisy)
  729.       {
  730.         putchar('\n');
  731.         fflush(stdout);
  732.       }
  733.       perror("zip warning");
  734.       warn("could not open for reading: ", z->name);
  735.       free((voidp *)(z->name));
  736.       free((voidp *)(z->zname));
  737.       farfree((voidp far *)z);
  738.     }
  739.     else
  740.     {
  741.       *w = z;
  742.       w = &z->nxt;
  743.       zcount++;
  744.     }
  745.   }
  746.   if (key != NULL)
  747.   {
  748.     free((voidp *)key);
  749.     key = NULL;
  750.   }
  751.  
  752.  
  753.   /* Get one line comment for each new entry */
  754.   if (comadd)
  755.   {
  756.     if ((e = malloc(MAXCOM + 1)) == NULL)
  757.       err(ZE_MEM, "was reading comment lines");
  758.     for (z = zfiles; z != NULL; z = z->nxt)
  759.       if (z->mark)
  760.       {
  761.         if (noisy)
  762.           printf("Enter comment for %s:\n", z->name);
  763.         if (fgets(e, MAXCOM+1, stdin) != NULL)
  764.         {
  765.           if ((p = malloc((k = strlen(e))+1)) == NULL)
  766.           {
  767.             free((voidp *)e);
  768.             err(ZE_MEM, "was reading comment lines");
  769.           }
  770.           strcpy(p, e);
  771.           if (p[k-1] == '\n')
  772.             p[--k] = 0;
  773.           z->comment = p;
  774.           z->com = k;
  775.         }
  776.       }
  777.     free((voidp *)e);
  778.   }
  779.  
  780.   /* Get multi-line comment for the zip file */
  781.   if (zipedit)
  782.   {
  783.     if ((e = malloc(MAXCOM + 1)) == NULL)
  784.       err(ZE_MEM, "was reading comment lines");
  785.     if (noisy && zcomlen)
  786.     {
  787.       puts("current zip file comment is:");
  788.       fwrite(zcomment, 1, zcomlen, stdout);
  789.       if (zcomment[zcomlen-1] != '\n')
  790.         putchar('\n');
  791.       free((voidp *)zcomment);
  792.     }
  793.     zcomment = malloc(1);
  794.     *zcomment = 0;
  795.     if (noisy)
  796.       puts("enter new zip file comment (end with .):");
  797.     while (fgets(e, MAXCOM+1, stdin) != NULL && strcmp(e, ".\n"))
  798.     {
  799.       if (e[(r = strlen(e)) - 1] == '\n')
  800.         e[--r] = 0;
  801.       if ((p = malloc((*zcomment ? strlen(zcomment) + 3 : 1) + r)) == NULL)
  802.       {
  803.         free((voidp *)e);
  804.         err(ZE_MEM, "was reading comment lines");
  805.       }
  806.       if (*zcomment)
  807.         strcat(strcat(strcpy(p, zcomment), "\r\n"), e);
  808.       else
  809.         strcpy(p, *e ? e : "\r\n");
  810.       free((voidp *)zcomment);
  811.       zcomment = p;
  812.     }
  813.     zcomlen = strlen(zcomment);
  814.     free((voidp *)e);
  815.   }
  816.  
  817.  
  818.   /* Write central directory and end header to temporary zip */
  819.   diag("writing central directory");
  820.   k = 0;                        /* keep count for end header */
  821.   if ((c = ftell(y)) == -1L)    /* get start of central */
  822.     err(d ? ZE_WRITE : ZE_TEMP, tempzip);
  823.   n = t = 0;
  824.   for (z = zfiles; z != NULL; z = z->nxt)
  825.   {
  826.     if ((r = putcentral(z, y)) != ZE_OK)
  827.       err(r, tempzip);
  828.     n += z->len;
  829.     t += z->siz;
  830.     k++;
  831.   }
  832.   if (k == 0)
  833.     warn("zip file empty", "");
  834.   if (verbose)
  835.     printf("total bytes=%lu, compressed=%lu -> %d%% savings\n",
  836.            n, t, percent(n, t));
  837.   if ((t = ftell(y)) == -1L)    /* get end of central */
  838.     err(d ? ZE_WRITE : ZE_TEMP, tempzip);
  839.   t -= c;                       /* compute length of central */
  840.   diag("writing end of central directory");
  841.   if ((r = putend(k, t, c, zcomlen, zcomment, y)) != ZE_OK)
  842.     err(r, tempzip);
  843.   tempzf = NULL;
  844.   if (fclose(y))
  845.     err(d ? ZE_WRITE : ZE_TEMP, tempzip);
  846.  
  847.  
  848.   /* Replace old zip file with new zip file, leaving only the new one */
  849.   if (!d)
  850.   {
  851.     diag("replacing old zip file with new zip file");
  852.     if ((r = replace(zipfile, tempzip)) != ZE_OK)
  853.     {
  854.       warn("new zip file left as: ", tempzip);
  855.       free((voidp *)tempzip);
  856.       tempzip = NULL;
  857.       err(r, "was replacing the original zip file");
  858.     }
  859.     free((voidp *)tempzip);
  860.   }
  861.   tempzip = NULL;
  862.   setfileattr(zipfile, a);
  863.  
  864.   /* Finish up (process -o, -m, clean up).  Exit code depends on o. */
  865.   leave(o ? ZE_OPEN : ZE_OK);
  866. }
  867.